package core;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;

import org.lwjgl.BufferUtils;

import static org.lwjgl.opengl.GL11.*;
import de.matthiasmann.twl.utils.PNGDecoder;

/**
 * A Texture2D is an image inside the OpenGL context
 * that can be used to add colour data to a fragment inside the 
 * fragment shader.
 * NOTE: Currently this can only take .png as a texture format. 
 */
public class Texture2D {
   /**The width of this texture**/
   private int width;
   /**The height of this texture**/
   private int height;
   /**The OpenGL reference of this texture**/
   private int glRef;
   
   /**
    * Constructs a new {@link Texture2D}
    * @param png the {@link URL} to the .png file to use as this texture
    */
   public Texture2D(String png){
      glRef = glGenTextures();
      load(png);
   }//End constructor

   public void load(String png) {
      try {
         URL url = getClass().getClassLoader().getResource(png);
         //Setup the PNG decoder
         InputStream input = url.openStream();
         PNGDecoder decoder = new PNGDecoder(input);
         width = decoder.getWidth();
         height = decoder.getHeight();
         //Create the texture in openGL
         glBindTexture(GL_TEXTURE_2D, glRef);
         //Load the png information from the PNG decoder
         ByteBuffer buffer = BufferUtils.createByteBuffer(4 * width * height);
         decoder.decode(buffer, width * 4, PNGDecoder.Format.RGBA);
         buffer.flip();
         
         //Set the default texture parameters //TODO maybe add some options to specify these
         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
         //load the texture data into graphics memory
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
         glBindTexture(GL_TEXTURE_2D, 0);
         input.close();
      } catch (IOException e) {
         e.printStackTrace();
      }//End try catch
   }
   
   /**
    * Constructs an empty Texture2D.
    */
   public Texture2D(){
      glRef = glGenTextures();
   }//End constructor
   
   /**
    * Method to bind this texture to OpenGL
    */
   public void bind(){
      glBindTexture(GL_TEXTURE_2D, glRef);
   }//End method bind
   
   /**
    * Method to unbind this texture from OpenGL
    */
   public void unbind(){
      glBindTexture(GL_TEXTURE_2D, 0);
   }//End method unbind

   /**
    * Gets the width of this texture
    * @return the width of this texture
    */
   public int getWidth() {
      return width;
   }//End method getWidth
   
   /**
    * Sets the width of this texture, should only be done by the core software
    * @param width the width to set
    */
   void setWidth(int width){
      this.width = width;
   }//End method setWidth
   
   /**
    * Gets the height of this texture
    * @return the height of this texture
    */
   public int getHeight(){
      return height;
   }//End method getHeight
   
   /**
    * Sets the height of this texture, should only be done by the core software
    * @param height the height to set
    */
   void setHeight(int height){
      this.height = height;
   }//end method setHeight

   /**
    * Gets the OpenGL reference of this texture
    * @return the OpenGL reference of this texture
    */
   public int getRef() {
      return glRef;
   }//End method getRef
}//End class Texture2D
